/**
 * ZHU framework. Copyright 2012-, all rights reserved.
 *
 * $Id: WebDownloadContext.java 12 2012-07-27 08:48:07Z zhuxiaopeng $
 * $Revision: 12 $
 * $Date: 2012-07-27 16:48:07 +0800 (五, 2012-07-27) $
 * $Author: zhuxiaopeng $
 */
package zhu.framework.web;

import java.util.logging.*;

import zhu.framework.util.*;

/**
 * <p>
 * </p>
 * 
 * @author $Author: zhuxiaopeng $
 * @version $Revision: 12 $ - $Date: 2012-07-27 16:48:07 +0800 (五, 2012-07-27) $
 */
public final class WebDownloadContext {
	/**
	 * Microsoft Excelファイル用の<code>contentType</code>値。
	 */
	static public final String MS_EXCEL_CONTENT_TYPE = "application/vnd.ms-excel";

	/**
	 * PDFファイル用の<code>contentType</code>値。
	 */
	static public final String PDF_CONTENT_TYPE = "application/pdf";

	/**
	 * このClassのデフォルトの<code>Logger</code>取得する。
	 * 特に理由のない限り、このClass内ではこのメソッドを通じてLoggerを取得することを推奨する。
	 * 
	 * @return このClassのデフォルトの<code>Logger</code>
	 */
	static private Logger getLogger() {
		final LoggerManager manager = LoggerManager.getInstance();
		final Logger logger = manager.getLogger(WebDownloadContext.class);
		return logger;
	}

	/**
	 * <p>
	 * 指定された情報を用いてこのコンテキスト情報を初期化する。 次の呼び出しと等価である。
	 * <code>{@link #WebDownloadContext(String, ContentDispositionType, String, String) WebDownloadContext(contentType, ContentDispositionType.ATTACHMENT, null, null)}</code>
	 * </p>
	 * 
	 * @param contentType
	 *            ダウンロード・セッションのContent Type
	 */
	public WebDownloadContext(final String contentType) {
		this(contentType, ContentDispositionType.ATTACHMENT, null, null);
	}

	/**
	 * <p>
	 * 指定された情報を用いてこのコンテキスト情報を初期化する。 次の呼び出しと等価である。
	 * <code>{@link #WebDownloadContext(String, ContentDispositionType, String, String) WebDownloadContext(contentType, ContentDispositionType.ATTACHMENT, filename, null)}</code>
	 * </p>
	 * 
	 * @param contentType
	 *            ダウンロード・セッションのContent Type
	 * @param filename
	 *            クライアント側に提示するファイル名、または<code>null</code>
	 */
	public WebDownloadContext(final String contentType, final String filename) {
		this(contentType, ContentDispositionType.ATTACHMENT, filename, null);
	}

	/**
	 * <p>
	 * 指定された情報を用いてこのコンテキスト情報を初期化する。 次の呼び出しと等価である。
	 * <code>{@link #WebDownloadContext(String, ContentDispositionType, String, String) WebDownloadContext(contentType, ContentDispositionType.ATTACHMENT, filename, filenameEncoding)}</code>
	 * </p>
	 * 
	 * @param contentType
	 *            ダウンロード・セッションのContent Type
	 * @param filename
	 *            クライアント側に提示するファイル名、または<code>null</code>
	 * @param filenameEncoding
	 *            クライアント側に提示するファイル名のエンコーディング、または<code>null</code>。
	 *            <code>null</code>の場合は&quot;UTF-8&quot;がプロパティに設定される
	 */
	public WebDownloadContext(final String contentType, final String filename, final String filenameEncoding) {
		this(contentType, ContentDispositionType.ATTACHMENT, filename, filenameEncoding);
	}

	/**
	 * <p>
	 * 指定された情報を用いてこのコンテキスト情報を初期化する。 次の呼び出しと等価である。
	 * <code>{@link #WebDownloadContext(String, ContentDispositionType, String, String) WebDownloadContext(contentType, dispositionType, filename, null)}</code>
	 * </p>
	 * 
	 * @param contentType
	 *            ダウンロード・セッションのContent Type
	 * @param dispositionType
	 *            ContentDispositionの種別
	 * @param filename
	 *            クライアント側に提示するファイル名、または<code>null</code>
	 * @param filenameEncoding
	 *            クライアント側に提示するファイル名のエンコーディング、または<code>null</code>。
	 *            <code>null</code>の場合は&quot;UTF-8&quot;がプロパティに設定される
	 */
	public WebDownloadContext(final String contentType, final ContentDispositionType dispositionType, final String filename) {
		this(contentType, dispositionType, filename, null);
	}

	/**
	 * <p>
	 * 指定された情報を用いてこのコンテキスト情報を初期化する。 引数の値によって対応する名前のプロパティを初期化する。 但し、
	 * <code>filenameEncoding</code>に関しては、値が<code>null</code>
	 * の場合にはデフォルト値&quot;UTF-8&quot;がプロパティに設定される。
	 * </p>
	 * 
	 * @param contentType
	 *            ダウンロード・セッションのContent Type
	 * @param dispositionType
	 *            ContentDispositionの種別
	 * @param filename
	 *            クライアント側に提示するファイル名、または<code>null</code>
	 * @param filenameEncoding
	 *            クライアント側に提示するファイル名のエンコーディング、または<code>null</code>。
	 *            <code>null</code>の場合は&quot;UTF-8&quot;がプロパティに設定される
	 * @throws NullPointerException
	 *             <code>contentType==null</code>または
	 *             <code>dispositionType==null</code>の場合
	 */
	public WebDownloadContext(final String contentType, final ContentDispositionType dispositionType, final String filename,
			final String filenameEncoding) {
		MyUtility.checkMethodParameterNotNull("contentType", contentType);
		MyUtility.checkMethodParameterNotNull("dispositionType", dispositionType);
		//
		this.contentType = contentType;
		this.filename = filename;
		this.contentDispositionType = dispositionType;
		if (filenameEncoding != null) {
			this.filenameEncoding = filenameEncoding;
		} else {
			this.filenameEncoding = "UTF-8";
		}
	}

	/**
	 * <p>
	 * ファイルのDownload処理においてクライアント側に提示したいファイル名を取得する。 このプロパティが<code>null</code>
	 * の場合は、クライアント側にはファイル名は提示されない。
	 * </p>
	 * 
	 * @return ファイルのDownload処理においてクライアント側に提示したいファイル名、または<code>null</code>
	 */
	public String getFilename() {
		return filename;
	}

	/**
	 * <p>
	 * ファイルのDownload処理においてクライアント側に提示したいファイル名を設定する。 このプロパティが<code>null</code>
	 * の場合は、クライアント側にはファイル名は提示されない。 いくつかの典型的な値はこのclassに定数として定義されている。
	 * </p>
	 * 
	 * @param filename
	 *            ファイルのDownload処理においてクライアント側に提示したいファイル名、または<code>null</code>
	 */
	public void setFilename(final String filename) {
		checkReadonly();
		this.filename = filename;
	}

	/**
	 * <p>
	 * このコンテキスト情報が関連づけられるDownloadセッションのContent Typeを取得する。
	 * いくつかの典型的な値はこのclassに定数として定義されている。
	 * </p>
	 * 
	 * @return このコンテキスト情報が関連づけられるDownloadセッションのContent Type
	 */
	public String getContentType() {
		assert (contentType != null);
		return contentType;
	}

	/**
	 * <p>
	 * このコンテキスト情報が関連づけられるDownloadセッションのContent Typeを設定する。
	 * </p>
	 * 
	 * @param contentType
	 *            このコンテキスト情報が関連づけられるDownloadセッションのContent Type
	 * @throws NullPointerException
	 *             <code>contentType==null</code>の場合
	 */
	public void setContentType(final String contentType) {
		MyUtility.checkMethodParameterNotNull("contentType", contentType);
		checkReadonly();
		//
		this.contentType = contentType;
	}

	/**
	 * <p>
	 * クライアント側へ提示する{@link #getFilename() ファイル名}のエンコーディングを設定する。
	 * デフォルトは&quot;UTF-8&quot;である。
	 * </p>
	 * 
	 * @param filenameEncoding
	 *            クライアント側へ提示する{@link #getFilename() ファイル名}のエンコーディング
	 * @throws NullPointerException
	 *             <code>filenameEncoding==null</code>の場合
	 */
	public void setFilenameEncoding(final String filenameEncoding) {
		MyUtility.checkMethodParameterNotNull("filenameEncoding", filenameEncoding);
		checkReadonly();
		//
		this.filenameEncoding = filenameEncoding;
	}

	/**
	 * <p>
	 * クライアント側へ提示する{@link #getFilename() ファイル名}のエンコーディングを取得する。
	 * デフォルトは&quot;UTF-8&quot;である。
	 * </p>
	 * 
	 * @return クライアント側へ提示する{@link #getFilename() ファイル名}のエンコーディング
	 */
	public String getFilenameEncoding() {
		assert (filenameEncoding != null);
		return filenameEncoding;
	}

	/**
	 * <p>
	 * プロパティ<code>contentDispositionType</code>の値を設定する。
	 * </p>
	 * 
	 * @param contentDispositionType
	 *            プロパティ<code>contentDispositionType</code>に設定する値
	 * @throws NullPointerException
	 *             <code>contentDispositionType==null</code>の場合
	 */
	public void setContentDispositionType(final ContentDispositionType contentDispositionType) {
		MyUtility.checkMethodParameterNotNull("contentDispositionType", contentDispositionType);
		checkReadonly();
		//
		this.contentDispositionType = contentDispositionType;
	}

	/**
	 * <p>
	 * プロパティ<code>contentDispositionType</code>の値を取得する。
	 * </p>
	 * 
	 * @return プロパティ<code>contentDispositionType</code>の値
	 */
	public ContentDispositionType getContentDispositionType() {
		assert (contentDispositionType != null);
		return contentDispositionType;
	}

	/**
	 * <p>
	 * このコンテキスト情報を変更不可能にする。
	 * </p>
	 */
	public void setReadonly() {
		this.readonly = true;
	}

	/**
	 * <p>
	 * このコンテキスト情報が変更可能かどうかを取得する。
	 * </p>
	 * 
	 * @return コンテキスト情報が変更不能であれば<code>true</code>、それ以外は<code>false</code>
	 */
	public boolean isReadonly() {
		return readonly;
	}

	@Override
	public String toString() {
		final ToStringBuilder builder = new ToStringBuilder(WebDownloadContext.class);
		builder.append("contentType", getContentType());
		builder.append("contentDispositionType", getContentDispositionType());
		builder.append("filename", getFilename());
		builder.append("filenameEncoding", getFilenameEncoding());
		builder.append("readonly", isReadonly());
		//
		return builder.toString();
	}

	private void checkReadonly() {
		if (isReadonly()) {
			final IllegalArgumentException e = new IllegalArgumentException(String.format("Attempt to modify a readonly context : %s", this));
			final Logger logger = getLogger();
			logger.throwing("educom.framework.web.WebDownloadContext", "checkReadonly", e);
			throw e;
		}
	}

	private String contentType;
	private String filename;
	private String filenameEncoding;
	private boolean readonly;
	private ContentDispositionType contentDispositionType;
}
